#include "../../Coroutine/IOManager.hpp"
#include "../../base/BaseLog.hpp"
#include "../../Coroutine/Fiber.hpp"
#include <cassert>
#include <functional>
#include <unistd.h>
#include <vector>

using namespace DBServer::coroutine;

#define CREATE_PIPE(X)                                                \
    std::vector<std::vector<int>> fds = []()                          \
    {                                                                 \
        int fds[X][2];                                                \
        std::vector<std::vector<int>> fd_vet(X, std::vector<int>(2)); \
        for (int i = 0; i < X; ++i)                                   \
        {                                                             \
            pipe(fds[i]);                                             \
            fd_vet[i][0] = fds[i][0];                                 \
            fd_vet[i][1] = fds[i][1];                                 \
                                                                      \
            char buf[1];                                              \
            int ret = write(fd_vet[i][1], buf, 1);                    \
            assert(ret == 1);                                         \
            ret = read(fd_vet[i][0], buf, 1);                         \
            assert(ret == 1);                                         \
        }                                                             \
                                                                      \
        info("create pipe\n");                                        \
        return fd_vet;                                                \
    }()

#define TEST_SINGEL(X)                                                                                           \
    void task##X(IOManager *io_mgr)                                                                              \
    {                                                                                                            \
        std::function<void()> read_cb = []()                                                                     \
        {                                                                                                        \
            char buf[1];                                                                                         \
            read(fds[X - 1][0], buf, 1);                                                                         \
            debug("TEST(%d) Fiber(%d) read fd(%d) -> %c\n", X, Fiber::GetThis()->get_id(), fds[X - 1][0], buf);  \
        };                                                                                                       \
                                                                                                                 \
        std::function<void()> write_cb = []()                                                                    \
        {                                                                                                        \
            char buf = (char)('a' + 1);                                                                          \
            write(fds[X - 1][1], &buf, 1);                                                                       \
            debug("TEST(%d) Fiber(%d) write fd(%d) -> %c\n", X, Fiber::GetThis()->get_id(), fds[X - 1][1], buf); \
        };                                                                                                       \
                                                                                                                 \
        io_mgr->add_ev(fds[X - 1][0], IOEvent::READ, read_cb);                                                   \
        io_mgr->add_ev(fds[X - 1][1], IOEvent::WRITE, write_cb);                                                 \
    }

CREATE_PIPE(100);

TEST_SINGEL(1)
TEST_SINGEL(2)
TEST_SINGEL(3)
TEST_SINGEL(4)
TEST_SINGEL(5)
TEST_SINGEL(6)
TEST_SINGEL(7)
TEST_SINGEL(8)
TEST_SINGEL(9)
TEST_SINGEL(10)
TEST_SINGEL(11)
TEST_SINGEL(12)
TEST_SINGEL(13)
TEST_SINGEL(14)
TEST_SINGEL(15)
TEST_SINGEL(16)
TEST_SINGEL(17)
TEST_SINGEL(18)
TEST_SINGEL(19)
TEST_SINGEL(20)
TEST_SINGEL(21)
TEST_SINGEL(22)
TEST_SINGEL(23)
TEST_SINGEL(24)
TEST_SINGEL(25)
TEST_SINGEL(26)
TEST_SINGEL(27)
TEST_SINGEL(28)
TEST_SINGEL(29)
TEST_SINGEL(30)
TEST_SINGEL(31)
TEST_SINGEL(32)
TEST_SINGEL(33)
TEST_SINGEL(34)
TEST_SINGEL(35)
TEST_SINGEL(36)
TEST_SINGEL(37)
TEST_SINGEL(38)
TEST_SINGEL(39)
TEST_SINGEL(40)
TEST_SINGEL(41)
TEST_SINGEL(42)
TEST_SINGEL(43)
TEST_SINGEL(44)
TEST_SINGEL(45)
TEST_SINGEL(46)
TEST_SINGEL(47)
TEST_SINGEL(48)
TEST_SINGEL(49)
TEST_SINGEL(50)
TEST_SINGEL(51)
TEST_SINGEL(52)
TEST_SINGEL(53)
TEST_SINGEL(54)
TEST_SINGEL(55)
TEST_SINGEL(56)
TEST_SINGEL(57)
TEST_SINGEL(58)
TEST_SINGEL(59)
TEST_SINGEL(60)
TEST_SINGEL(61)
TEST_SINGEL(62)
TEST_SINGEL(63)
TEST_SINGEL(64)
TEST_SINGEL(65)
TEST_SINGEL(66)
TEST_SINGEL(67)
TEST_SINGEL(68)
TEST_SINGEL(69)
TEST_SINGEL(70)
TEST_SINGEL(71)
TEST_SINGEL(72)
TEST_SINGEL(73)
TEST_SINGEL(74)
TEST_SINGEL(75)
TEST_SINGEL(76)
TEST_SINGEL(77)
TEST_SINGEL(78)
TEST_SINGEL(79)
TEST_SINGEL(80)
TEST_SINGEL(81)
TEST_SINGEL(82)
TEST_SINGEL(83)
TEST_SINGEL(84)
TEST_SINGEL(85)
TEST_SINGEL(86)
TEST_SINGEL(87)
TEST_SINGEL(88)
TEST_SINGEL(89)
TEST_SINGEL(90)
TEST_SINGEL(91)
TEST_SINGEL(92)
TEST_SINGEL(93)
TEST_SINGEL(94)
TEST_SINGEL(95)
TEST_SINGEL(96)
TEST_SINGEL(97)
TEST_SINGEL(98)
TEST_SINGEL(99)
TEST_SINGEL(100)

void test() {
    info("-----------------------test singel thread io manager--------------------------\n");
    IOManager io_mgr{1, false, "singel thread io manager"};

    io_mgr.start();

    task1(&io_mgr);
    task2(&io_mgr);
    task3(&io_mgr);
    task4(&io_mgr);
    task5(&io_mgr);

    info("io manager start\n");

    io_mgr.stop();
   info("io manager finish task\n");

    info("------------------------test singel thread io manager pass ! ------------------------------\n");
}





void test_multi() {
    info("------------------------------test mutil thread io manager--------------------------\n");

    IOManager io_mgr{4, false, "singel thread io manager"};

    io_mgr.start();

    task1(&io_mgr);
    task2(&io_mgr);
    task3(&io_mgr);
    task4(&io_mgr);
    task5(&io_mgr);
    task6(&io_mgr);
    task7(&io_mgr);
    task8(&io_mgr);
    task9(&io_mgr);
    task10(&io_mgr);
    task11(&io_mgr);
    task12(&io_mgr);
    task13(&io_mgr);
    task14(&io_mgr);
    task15(&io_mgr);
    task16(&io_mgr);
    task17(&io_mgr);
    task18(&io_mgr);
    task19(&io_mgr);
    task20(&io_mgr);
    task21(&io_mgr);
    task22(&io_mgr);
    task23(&io_mgr);
    task24(&io_mgr);
    task25(&io_mgr);
    task26(&io_mgr);
    task27(&io_mgr);
    task28(&io_mgr);
    task29(&io_mgr);
    task30(&io_mgr);
    task31(&io_mgr);
    task32(&io_mgr);
    task33(&io_mgr);
    task34(&io_mgr);
    task35(&io_mgr);
    task36(&io_mgr);
    task37(&io_mgr);
    task38(&io_mgr);
    task39(&io_mgr);
    task40(&io_mgr);
    task41(&io_mgr);
    task42(&io_mgr);
    task43(&io_mgr);
    task44(&io_mgr);
    task45(&io_mgr);
    task46(&io_mgr);
    task47(&io_mgr);
    task48(&io_mgr);
    task49(&io_mgr);
    task50(&io_mgr);
    task51(&io_mgr);
    task52(&io_mgr);
    task53(&io_mgr);
    task54(&io_mgr);
    task55(&io_mgr);
    task56(&io_mgr);
    task57(&io_mgr);
    task58(&io_mgr);
    task59(&io_mgr);
    task60(&io_mgr);
    task61(&io_mgr);
    task62(&io_mgr);
    task63(&io_mgr);
    task64(&io_mgr);
    task65(&io_mgr);
    task66(&io_mgr);
    task67(&io_mgr);
    task68(&io_mgr);
    task69(&io_mgr);
    task70(&io_mgr);
    task71(&io_mgr);
    task72(&io_mgr);
    task73(&io_mgr);
    task74(&io_mgr);
    task75(&io_mgr);
    task76(&io_mgr);
    task77(&io_mgr);
    task78(&io_mgr);
    task79(&io_mgr);
    task80(&io_mgr);
    task81(&io_mgr);
    task82(&io_mgr);
    task83(&io_mgr);
    task84(&io_mgr);
    task85(&io_mgr);
    task86(&io_mgr);
    task87(&io_mgr);
    task88(&io_mgr);
    task89(&io_mgr);
    task90(&io_mgr);
    task91(&io_mgr);
    task92(&io_mgr);
    task93(&io_mgr);
    task94(&io_mgr);
    task95(&io_mgr);
    task96(&io_mgr);
    task97(&io_mgr);
    task98(&io_mgr);
    task99(&io_mgr);
    task100(&io_mgr);

    info("io manager start\n");

    io_mgr.stop();

    info("-----------------------------------test mutil thread io manager pass-----------------------\n");
}

int main(int argc, const char** argv) {
    test();
    test_multi();
    return 0;
}